package com.goldsprite.microhorigame.systems;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Array;
import com.goldsprite.gameframeworks.assets.GameRes;
import com.goldsprite.gameframeworks.ecs.SpriteUtils;
import com.goldsprite.gameframeworks.ecs.component.*;
import com.goldsprite.gameframeworks.ecs.entity.GObject;
import com.goldsprite.gameframeworks.utils.math.Vector2;
import com.goldsprite.gameframeworks.utils.math.Vector2Int;
import com.goldsprite.gameframeworks.utils.*;
import com.goldsprite.microhorigame.ecs.EntityFsmComponent;
import com.goldsprite.microhorigame.ecs.EntityInputComponent;
import com.goldsprite.microhorigame.ecs.EntityPropsComponent;
import com.goldsprite.microhorigame.ecs.MonsterPortalComponent;
import com.goldsprite.microhorigame.ecs.fsms.states.EntityDeathState;
import com.goldsprite.microhorigame.ecs.fsms.states.EntityHurtState;
import com.goldsprite.microhorigame.ecs.fsms.states.*;
import com.goldsprite.gameframeworks.log.*;
import com.goldsprite.microhorigame.screens.games.MonsterType;

public class GObjectGenerator {

	private static float objScale = 1;

	public static GObject newGlow(float x, float y) {
		GObject obj = new GObject() {{
			setName("Glow");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		SpriteComponent sprite = obj.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Foreground");
		sprite.setPivot(Pivot.Center);
		sprite.setRegion(GameRes.Glow);
		sprite.getScale().set(0.6f);

		return obj;
	}


	public static GObject newMonsterDoor(float x, float y) {
		GObject obj = new GObject() {{
			setName("MonsterDoor");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		SpriteComponent sprite = obj.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Background");
		sprite.setPivot(Pivot.LeftDown);
		sprite.setOriginOffset(16, 0);
		sprite.setRegion(GameRes.Monster_Door);
		sprite.getScale().set(2.2f, 3f);

		return obj;
	}


	public static GObject newGolem(float x, float y) {
		GameRes res = GameRes.Golem;
		float scl = 1.2f;
		int startFaceX = -1;
		AnimatorComponent animator = new AnimatorComponent();
		SpriteUtils.setUVUnit(res.getUVUnit());
		animator.addAnim("Idle", new Animation<>(.15f, SpriteUtils.splitFrames(res, 0, 8), Animation.PlayMode.LOOP));
		animator.addAnim("Move", new Animation<>(.28f, SpriteUtils.splitFrames(res, 1, 10), Animation.PlayMode.LOOP));
		animator.addAnim("Hurt", new Animation<>(.14f, SpriteUtils.splitFrames(res, 2, 4), Animation.PlayMode.NORMAL));
		animator.addAnim("Attack", new Animation<>(.14f, SpriteUtils.splitFrames(res, 3, 11), Animation.PlayMode.NORMAL));
		animator.addAnim("Death", new Animation<>(.15f, SpriteUtils.splitFrames(res, 4, 13), Animation.PlayMode.NORMAL));
		return newMonsterEntity(x, y, res, scl, startFaceX, animator);
	}


	public static GObject newBlackCanine(float x, float y) {
		GameRes res = GameRes.BlackCanine;
		float scl = 1.2f;
		int startFaceX = -1;
		AnimatorComponent animator = new AnimatorComponent();
		SpriteUtils.setUVUnit(res.getUVUnit());
		animator.addAnim("Idle", new Animation<>(.15f, SpriteUtils.splitFrames(res, 0, 4), Animation.PlayMode.LOOP));
		animator.addAnim("Move", new Animation<>(.22f, SpriteUtils.splitFrames(res, 1, 5), Animation.PlayMode.LOOP));
		animator.addAnim("Hurt", new Animation<>(.14f, SpriteUtils.splitFrames(res, 2, 2), Animation.PlayMode.NORMAL));
		animator.addAnim("Attack", new Animation<>(.15f, SpriteUtils.splitFrames(res, 3, 8), Animation.PlayMode.NORMAL));
		animator.addAnim("Death", new Animation<>(.15f, SpriteUtils.splitFrames(res, 5, 8), Animation.PlayMode.NORMAL));
		return newMonsterEntity(x, y, res, scl, startFaceX, animator);
	}


	public static GObject newDemonRat(float x, float y) {
		GameRes res = GameRes.DemonRat;
		float scl = 1f;
		int startFaceX = -1;
		AnimatorComponent animator = new AnimatorComponent();
		SpriteUtils.setUVUnit(res.getUVUnit());
		animator.addAnim("Idle", new Animation<>(.15f, SpriteUtils.splitFrames(res, 0, 6), Animation.PlayMode.LOOP));
		animator.addAnim("Move", new Animation<>(.22f, SpriteUtils.splitFrames(res, 1, 6), Animation.PlayMode.LOOP));
		animator.addAnim("Hurt", new Animation<>(.14f, SpriteUtils.splitFrames(res, 2, 2), Animation.PlayMode.NORMAL));
		animator.addAnim("Attack", new Animation<>(.15f, SpriteUtils.splitFrames(res, 3, 6), Animation.PlayMode.NORMAL));
		animator.addAnim("Death", new Animation<>(.15f, SpriteUtils.splitFrames(res, 4, 6), Animation.PlayMode.NORMAL));
		return newMonsterEntity(x, y, res, scl, startFaceX, animator);
	}


	public static GObject newMonsterEntity(float x, float y, GameRes res, float scl, int startFaceX, AnimatorComponent animator) {
		String name = res.name();
		int[] uvUnit = res.getUVUnit();
		Vector2Int bodySize = res.bodySize;
		String tag = "Monster";

		GObject obj = new GObject() {{
			setName(name);
			setTransform();
		}};
		obj.setTag(tag);
		obj.transform.setPosition(x, y);
		obj.transform.getFace().setX(startFaceX);

		SpriteComponent sprite = obj.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Entity");
		sprite.setPivot(Pivot.LeftDown);
		sprite.setOriginOffset(uvUnit[0] / 2f, 0);
		sprite.getScale().set(scl);

		RigidbodyComponent rigi = obj.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.DYNAMIC);

		RectColliderComponent bodyColl = obj.addComponent(RectColliderComponent.class);
		bodyColl.setLayerName("Monster");
		bodyColl.setTag("BodyColl");
		bodyColl.setSize(bodySize.intX * scl, bodySize.intY * scl);
		bodyColl.setOffset(0, bodySize.y / 2f * scl);

		obj.addComponent(animator);

		EntityInputComponent input = obj.addComponent(EntityInputComponent.class);
		input.setEnableUserInput(false);
		EntityPropsComponent props = obj.addComponent(EntityPropsComponent.class);

		EntityFsmComponent fsm = obj.addComponent(EntityFsmComponent.class);
		fsm.setName(name);
		fsm.onInitializeStates(() -> {
			fsm.addState(new EntityIdleState(), 0);
			//fsm.addState(new AnimatorShowState(), 0);
			fsm.addState(new EntityHurtState(), 3);
			fsm.addState(new EntityDeathState(), 4);
		});
		return obj;
	}


	public static void newGround(float x, float y, float width, float height) {
		GameRes res = GameRes.Ground;
		//TODO: GameRes真得整改了，不能再在构造函数瞎造了，得分化为不同的资源子类
		((Texture) res.getResource()).setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
		String spriteLayer = "Block";

		GObject ground = new GObject(){{
			setName("Ground");
			setTransform();
		}};
		TransformComponent groundTransform = ground.addComponent(TransformComponent.class);
		groundTransform.position.set(x, y);

		SpriteComponent sprite = ground.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer(spriteLayer);
		sprite.setRegion(res);

		float sclX = width / sprite.getRegion().getRegionWidth();
		float sclY = height / sprite.getRegion().getRegionHeight();
		sprite.setScale(sclX, sclY); // 宽地面
		Vector2 renderSize = sprite.getRenderSize();
		sprite.setScale(1, 1);
		sprite.setColor(Color.WHITE); // 设置地面颜色
		sprite.getRegion().setRegion(0f, 0f, sclX, sclY);

		RigidbodyComponent rigi = ground.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.STATIC);

		int collOffsetPixelY = 1;

		RectColliderComponent collider = ground.addComponent(RectColliderComponent.class);
		collider.setTag("Ground");
		collider.setLayerName("Ground");
		collider.setSize(renderSize.x, renderSize.y - collOffsetPixelY);
		collider.setOffset(0, -collOffsetPixelY);

		Debug.log("地面顶部坐标: %s", sprite.getLeftDownPos().y + sprite.getRenderSize().y);
	}


	public static void newCamp1(float x, float y) {
		String name = "Camp1";
		String spriteLayer = "MiddleBackground";
		GameRes res = GameRes.Camp1;
		int[] uvUnit = res.getUVUnit();
		float scl = 1.6f;

		GObject obj = new GObject(){{
			setName(name);
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		SpriteComponent sprite = obj.addComponent(SpriteComponent.class);
		sprite.setPivot(Pivot.LeftDown);
		sprite.setOriginOffset(uvUnit[0] / 2f, 0);
		sprite.setSpriteLayer(spriteLayer);
		sprite.setRegion(res);
		sprite.getScale().set(scl);

		Debug.log("营帐底部坐标: %s", sprite.getLeftDownPos().y);
	}


	public static void newCampfire(float x, float y, float healAmount) {
		GObject obj = new GObject() {{
			setName("campfire");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		//元数据
		obj.metaDatas.put("healAmount", healAmount);

		SpriteComponent sprite = obj.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Block");
		sprite.setOriginOffset(0, -64);
		sprite.getScale().set(1 / 3f);

		AnimatorComponent animator = obj.addComponent(AnimatorComponent.class);
		animator.addAnim("Idle", new Animation<>(.22f, SpriteUtils.splitFrames(128, 128, GameRes.Block_Fire, 0, 5), Animation.PlayMode.LOOP));

		RigidbodyComponent rigi = obj.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.STATIC);

		CircleColliderComponent trigger = obj.addComponent(CircleColliderComponent.class);
		trigger.setRadius(200 * 1 / 3f);
		trigger.setTrigger(true);
		trigger.setLayerName("Default");
		trigger.onTriggerEnterEvent.add(c2 -> {
			if (!c2.getGObject().getTag().equals("Player")) return;
			EntityPropsComponent ent = c2.getComponent(EntityPropsComponent.class);
			ent.setNearCampfire(obj);
		});
		trigger.onTriggerExitEvent.add(c2 -> {
			if (!c2.getGObject().getTag().equals("Player")) return;
			EntityPropsComponent ent = c2.getComponent(EntityPropsComponent.class);
			ent.setNearCampfire(null);
		});
	}


	public static GObject newWall(float x, float y, float sizeX, float sizeY) {
		return newWall(x, y, sizeX, sizeY, true);
	}

	public static GObject newWall(float x, float y, float sizeX, float sizeY, boolean hasSprite) {
		return newWall(GameRes.Black, x, y, sizeX, sizeY, hasSprite);
	}

	public static GObject newWall(GameRes colorRes, float x, float y, float sizeX, float sizeY) {
		return newWall(colorRes, x, y, sizeX, sizeY, true);
	}

	public static GObject newWall(GameRes colorRes, float x, float y, float sizeX, float sizeY, boolean hasSprite) {
		GObject obj = new GObject() {{
			setName("Wall");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		if (hasSprite) {
			SpriteComponent wallSprite = obj.addComponent(new SpriteComponent());
			wallSprite.setSpriteLayer("Block");
			wallSprite.setRegion(colorRes);
			wallSprite.setScale(sizeX, sizeY);
		}

		RigidbodyComponent rigi = obj.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.STATIC);

		RectColliderComponent wallCollider = obj.addComponent(new RectColliderComponent());
		wallCollider.setTag("Ground");
		wallCollider.setLayerName("Ground");
		wallCollider.setSize(sizeX, sizeY);

		return obj;
	}

	public static GObject newPlatform(GameRes colorRes, float x, float y, float sizeX, float sizeY) {
		GObject obj = new GObject() {{
			setName("Platform");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		SpriteComponent wallSprite = obj.addComponent(new SpriteComponent());
		wallSprite.setSpriteLayer("Block");
		wallSprite.setRegion(colorRes);
		wallSprite.setScale(sizeX, sizeY);

		RigidbodyComponent rigi = obj.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.KINEMATIC);

		RectColliderComponent wallCollider = obj.addComponent(new RectColliderComponent());
		wallCollider.setTag("Ground");
		wallCollider.setLayerName("Ground");
		wallCollider.setSize(sizeX, sizeY);

		return obj;
	}


	static Array<TextureRegion> monsterPortalRegions;

	public static void newMonsterPortal(float x, float y, MonsterType monsterType) {
		if (monsterPortalRegions == null) {
			SpriteUtils.setUVUnit(256, 256);
			monsterPortalRegions = SpriteUtils.splitFrames(GameRes.Block_MonsterPortal, 0, 4);
		}

		GObject obj = new GObject() {{
			setName("MonsterPortal");
			setTransform();
		}};
		obj.transform.setPosition(x, y);

		RigidbodyComponent rigi = obj.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.STATIC);

		RectColliderComponent trigger = obj.addComponent(new RectColliderComponent());
		trigger.setTrigger(true);
		trigger.setLayerName("Default");
		trigger.setSize(200, 60);
		trigger.onTriggerEnterEvent.add(c2 -> {
		});

		SpriteComponent sprite = obj.addComponent(new SpriteComponent());
		sprite.setSpriteLayer("Background");
		sprite.setOriginOffset(0, -100);
		sprite.getScale().set(1 / 3f);

		WorldTxtComponent txt = obj.addComponent(new WorldTxtComponent());
		txt.initFnt(25);
		txt.isAlignCenter = true;
		txt.setSpriteLayer("WorldUI");
		txt.setText("怪物门-" + monsterType.name());
		txt.setOriginOffset(0, 200);

		AnimatorComponent animator = obj.addComponent(AnimatorComponent.class);
		animator.addAnim("Idle", new Animation<>(.22f, monsterPortalRegions, Animation.PlayMode.LOOP));

		MonsterPortalComponent monsterPortal = obj.addComponent(MonsterPortalComponent.class);
		monsterPortal.spawnMonsterType = monsterType;
	}

	public static void setObjScale(float objScale) {
		GObjectGenerator.objScale = objScale;
	}

	public static float getObjScale() {
		return objScale;
	}
}
